/*
	Program tworzący wirtualne karty sieciowe oraz sterowniki TAP dla nich.
	Sterownik TAP operuje na pakietach drugiej warstwy ISO/OSI.
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <net/if.h>
#include <linux/if_tun.h>
#include <sys/ioctl.h> 
#include <fcntl.h> 
#include <pthread.h>

#include "virtual.h"

/*
	Argumentami uruchamiania programu są numer pierwszego interfejsu oraz ich ilość, np. 1 10.
*/
int main(int argc, char *argv[]) 
{
	// ilość interfejsow
	int ilosc_interfejsow;
	// numer interfejsu
	int numer_interfejsu;
	// licznik pętli
	int i; 
	// polecenie do uruchamienia skryptu usuwającego stworzone interfejsy
	char polecenie[20];

	numer_interfejsu = atoi(argv[1]);
	ilosc_interfejsow = atoi(argv[2]);

	ilosc_urzadzen = 0;

    linksim = new_link_sim( ilosc_interfejsow, ilosc_interfejsow, urzadzenia );
	for (i = 1; i <= ilosc_interfejsow && i < MAKSYMALNA_LICZBA_URZADZEN; i++, numer_interfejsu++)
	{
		sprintf(urzadzenia[i-1].nazwa_urzadzenia, "tap%d", numer_interfejsu);
		stworzInterfejs(i-1, numer_interfejsu);
		
		// sprawdzenie czy udało się stworzyć interfejs
		if(urzadzenia[i-1].deskryptor_pliku < 0)
		{
			fprintf(stderr, "virtual: błąd podczas tworzenia interfejsu %s\n", urzadzenia[i-1].nazwa_urzadzenia);
			close(urzadzenia[i-1].deskryptor_pliku);
			// w tablicach zapisujemy tylko opisy stworzonych urządzeń, dlatego kolejne będzimy zapisywać w tym samym miejscu
		}
		else
		{
			initCRC32();
			// i tworzymy nowy wątek do obsługi tego urządzenia
			if (pthread_create(&urzadzenia[i-1].watek, NULL,  odbierzDane, (void*)(i-1)))
			{
				printf("virtual: błąd przy tworzeniu wątku dla urządzenia %s\n", urzadzenia[i-1].nazwa_urzadzenia);
				abort();
			}
			else
				// jeśli się udało to zwiększamy licznik urządzeń
				ilosc_urzadzen++;
		}
	}

    struct timespec ts;
    if( clock_gettime( CLOCK_REALTIME, &ts ) != 0 )
    {
        perror( "gettime" );
        exit( 1 );
    }

    while( 1 )
    {
        usleep(ITERATION_INTERVAL);
        pthread_mutex_lock( &link_mutex );
        link_simulate( linksim );
        
        struct timespec ts2;
        if( clock_gettime( CLOCK_REALTIME, &ts2 ) != 0 )
        {
            perror( "gettime" );
            exit( 1 );
        }
        uint elapsed = ( ts2.tv_sec - ts.tv_sec ) * 1000 + ( ts2.tv_nsec - ts.tv_nsec ) / 1000000;
        printf("simtime: %u simdelay: %u\nframes: %u elapsed: %u\n", linksim->simulation_time, linksim->simulated_time, linksim->processed_frames, elapsed );

        pthread_mutex_unlock( &link_mutex );
    }

	for (i = 0; i < ilosc_urzadzen; i++)
	{
		// czekamy na zakończenie wątku
		pthread_join(urzadzenia[i].watek, NULL);	
		// zamykamy plik
		close(urzadzenia[i].deskryptor_pliku);
		// usuwamy trwały interfejs
		sprintf(polecenie, "./virtualdel %s", urzadzenia[i-1].nazwa_urzadzenia);
		system(polecenie);
	}

	return 0;
}

int CRC32(char *ramka, int dlugosc_ramki)
{
	unsigned long ulCRC = 0xffffffff;

	while (dlugosc_ramki--)
        	ulCRC = (ulCRC >> 8) ^ crc32_table[(ulCRC & 0xFF) ^ *ramka++];
      
	return ulCRC ^ 0xffffffff; 
}

